<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript" src="../../jsunit/app/jsUnitCore.js"></script>
    <script type="text/javascript" src="../../../src/objx.test.js"></script>
	<script type="text/javascript" src="../../../src/objx.js"></script>
    <script type="text/javascript" src="../../../src/plugins/ioc/objx.ioc.js"></script>
    <script type="text/javascript">

		function test_namespace(){
		
			assertNotUndefined("objx", objx);
			assertNotUndefined("objx.ioc", objx.ioc);
			
		}

		function test_interfacesAndClasses()
		{
			assertNotUndefined("objx.ioc.Container", objx.ioc.Container);
		}

		function test_constructor()
		{
		
			var container = new objx.ioc.Container();
			
			assertNotUndefined("container.mappings should not be undefined", container.mappings);
			assertNotUndefined("container.instances should not be undefined", container.instances);
			assertNotNull("container.mappings should not be null", container.mappings);
			assertNotNull("container.instances should not be null", container.instances);
		
		}

		function test_addInterfaceAndClass()
		{
		
			var IService = Interface({});
			var Service = Class(IService, {});
			
			var container = new objx.ioc.Container();
			
			assertNotUndefined("container.set", container.set);
			
			// set an interface and class
			container.set("IService", Service);
			
			// make sure it was added
			
			assertNotUndefined("container.mappings[IService] expected to exist", container.mappings["IService"]);
			
			var mappingObj = container.mappings["IService"];
			
			assertNotUndefined("Since the object passed to 'set' is a Class, mappingObj.class should not be undefined.", mappingObj.klass);
		
		}
		
		function test_setChaining()
		{
		
			var container = new objx.ioc.Container();
			
			assertEquals(container, container.set("one", "one", "two"));
		
			container.set("two", "two", "two").set("three", "three", "three");
		
		}
		
		function test_getInstanceOfClassByInterface()
		{
		
			var IService = Interface({});
			var Service = Class(IService, {});
			
			var container = new objx.ioc.Container();
			
			// set an interface and class
			container.set("IService", Service);
			
			assertNotUndefined("container.get", container.get);
			
			var serviceInstance = container.get("IService");
			
			assertNotUndefined("serviceInstance", serviceInstance);
			assertNotNull("serviceInstance", serviceInstance);
			assertEquals("instance.type expected to equal the class", Service, serviceInstance.type);

		}
		
		function test_getInstanceOfClassByInterfaceIsSameInstance()
		{
		
			var IService = Interface({});
			var Service = Class(IService, {});
			
			var container = new objx.ioc.Container();
			
			// set an interface and class
			container.set("IService", Service);
			
			assertNotUndefined("container.get", container.get);
			
			var serviceInstance = container.get("IService");
			
			assertNotUndefined("serviceInstance", serviceInstance);
			assertNotNull("serviceInstance", serviceInstance);
			assertEquals("instance.type expected to equal the class", Service, serviceInstance.type);

			var anotherServiceInstance = container.get("IService");
			
			assertEquals("Both IService instances expected to be the same object and NOT two seperate instances.", serviceInstance, anotherServiceInstance);
		
		}
		
		function test_setAndGetClassByName()
		{
		
			var Service = Class({});
			
			var container = new objx.ioc.Container();
			
			container.set("DataService", Service);
			
			var serviceInstance = container.get("DataService");
		
			assertNotUndefined("serviceInstance", serviceInstance);
			assertNotNull("serviceInstance", serviceInstance);
			assertEquals("instance.type expected to equal the class", Service, serviceInstance.type);

		}
		
		function test_setInstance()
		{
		
			var IService = Interface({});
			var Service = Class(IService, {});
			var serviceInstance = new Service();
			
			var container = new objx.ioc.Container();
			
			// set the instance
			container.set("IService", serviceInstance);
		
			assertNotUndefined("container.mappings['IService'] expected to exist", container.mappings["IService"]);
			
			var mappingObj = container.mappings["IService"];
			
			assertNotUndefined("Since the object passed to 'set' is an instance, mappingObj.instance should not be undefined.", mappingObj.instance);

			// and try to get it
			var serviceInstanceReturned = container.get("IService");
			
			assertEquals("serviceInstance and serviceInstanceReturned expected to be identical", serviceInstance, serviceInstanceReturned);

		}
	
		function test_dependencyInjection_simple()
		{
		
			// setup some example interfaces and classes
		
			var IDataService = Interface({});
			var IServiceProvider = Interface({});
			var MyDataService = Class(IDataService, {
				init: function(_IServiceProvider){
					this.ServiceProvider = _IServiceProvider;
				}
			});
			var MyServiceProvider = Class(IServiceProvider, {
			});
			
			
			// create the container
			var container = new objx.ioc.Container();
			
			// set the mappings
			container.set("IDataService", MyDataService);
			container.set("IServiceProvider", MyServiceProvider);
			
			// test the 'getInstance' method
			assertNotUndefined("container.getInstance", container.getInstance);
		
			var instance = container.getInstance(MyDataService);
			
			assertNotUndefined("instance.ServiceProvider", instance.ServiceProvider);
			assertNotNull("instance.ServiceProvider", instance.ServiceProvider);
			
			assertEquals("instance.ServiceProvider.type expected to be MyServiceProvider.", MyServiceProvider, instance.ServiceProvider.type);
		
		}
		
		function test_multipleNested_dependencyInjection()
		{
		
			var IOneService = Interface({});
			var OneService = Class(IOneService, {});
			
			var ITwoService = Interface({});
			var TwoService = Class(ITwoService, { init: function(_IOneService){ this.IOneService = _IOneService; } });
			
			var IThreeService = Interface({});
			var ThreeService = Class(IThreeService, { init: function(_IOneService, _ITwoService){ this.IOneService = _IOneService; this.ITwoService = _ITwoService; } });
			
			var container = new objx.ioc.Container();
			
			container.set("IOneService", OneService);
			container.set("ITwoService", TwoService);
			container.set("IThreeService", ThreeService);
			
			var oneService = container.get("IOneService");
			var threeService = container.get("IThreeService");

			// make sure all other dependant services are provided too
			assertEquals("oneService should be threeService.IOneService", oneService, threeService.IOneService);
			assertEquals("oneService should be threeService.ITwoService.IOneService", oneService, threeService.ITwoService.IOneService);
		
		}
		
		function test_iocShortcutMethods()
		{
		
			var IOneService = Interface({});
			var OneService = Class(IOneService, {});
			
			var ITwoService = Interface({});
			var TwoService = Class(ITwoService, { init: function(_IOneService){ this.IOneService = _IOneService; } });
			
			var IThreeService = Interface({});
			var ThreeService = Class(IThreeService, { init: function(_IOneService, _ITwoService){ this.IOneService = _IOneService; this.ITwoService = _ITwoService; } });
			
			var container = new objx.ioc.Container();
			
			container.set("IOneService", IOneService, OneService);
			container.set("ITwoService", ITwoService, TwoService);
			container.set("IThreeService", IThreeService, ThreeService);
			
			assertNotUndefined("container.getIOneService()", container.getIOneService());
			assertNotUndefined("container.getITwoService()", container.getITwoService());
			assertNotUndefined("container.getIThreeService()", container.getIThreeService());

			assertEquals(container.get("IOneService"), container.getIOneService());
			assertEquals(container.get("ITwoService"), container.getITwoService());
			assertEquals(container.get("IThreeService"), container.getIThreeService());
		
		}
		
		function test_classWithAbstractBaseTreatedNormally()
		{
		
			var AbstractBase = AbstractClass({});
		
			var IOneService = Interface({});
			var OneService = Class(IOneService, {});
			
			var ITwoService = Interface({});
			var TwoService = Class(AbstractBase, ITwoService, { init: function(_IOneService){ this.IOneService = _IOneService; } });
			
			var IThreeService = Interface({});
			var ThreeService = Class(AbstractBase, IThreeService, { init: function(_IOneService, _ITwoService){ this.IOneService = _IOneService; this.ITwoService = _ITwoService; } });

			var container = new objx.ioc.Container();
			
			container.set("IOneService", IOneService, OneService);
			container.set("ITwoService", ITwoService, TwoService);
			container.set("IThreeService", IThreeService, ThreeService);
			
			assertNotUndefined("container.getIOneService()", container.getIOneService());
			assertNotUndefined("container.getITwoService()", container.getITwoService());
			assertNotUndefined("container.getIThreeService()", container.getIThreeService());

			assertEquals(container.get("IOneService"), container.getIOneService());
			assertEquals(container.get("ITwoService"), container.getITwoService());
			assertEquals(container.get("IThreeService"), container.getIThreeService());
		
		}
		
		function test_iocWithUndefinedOrNullObjectsWorks(){
		
			var IOneService = Interface({});
			var ITwoService = Interface({});
			
			var OneService = Class(IOneService, {
				init: function(_ITwoService){
					this.ITwoService = _ITwoService;
				}
			});
			
			var container = new objx.ioc.Container();
		
			container.set("IOneService", OneService);

			var o = container.get("IOneService");
			
			assertNotUndefined("o", o);
			assertNotNull("o", o);
			
			assertNull(o.ITwoService);

		}

		function test_containerHasMethod(){
		
			var container = new objx.ioc.Container();

			assertNotUndefined("container.has", container.has);
		
			var IService123 = Interface({});
			IService123.name = "IService123";
			var Service123 = Class(IService123, {});
			
			var IService456 = Interface({ m456: Method() });
			IService456.name = "IService456";
			
			container.set("IService123", IService123, Service123);
		
			assertTrue("container.has('IService123')", container.has("IService123"));
			assertFalse("container.has('IService456')", container.has("IService456"));
		
		}

    </script>
</head>
<body>
</body>
</html>